/*
	*@brief			：条件变量初始化，销毁
	*@param[cond]	:一个 pthread_cond_t 类型指针， 指向需要进行初始化操作的互斥锁对象；
	*@param[mutex]	:一个 pthread_mutex_t 类型指针， 指向需要进行初始化操作的互斥锁对象；
	*@param[attr]	:可将参数 attr 设置为 NULL，表示使用属性的默认值来初始化条件变量，与使用 PTHREAD_COND_INITIALIZER 宏相同。

	*@return 		:成功返回 0；失败将返回一个非 0 的错误码。
	*@others		:对于初始化与销毁操作，有以下问题需要注意：
						- 在使用条件变量之前必须对条件变量进行初始化操作，使用 PTHREAD_COND_INITIALIZER 宏或者函数 pthread_cond_init()都行；
						- 对已经初始化的条件变量再次进行初始化，将可能会导致未定义行为；
						- 对没有进行初始化的条件变量进行销毁，也将可能会导致未定义行为；
						- 对某个条件变量而言，仅当没有任何线程等待它时，将其销毁才是最安全的；
						- 经 pthread_cond_destroy()销毁的条件变量， 可以再次调用 pthread_cond_init()对其进行重新初始化。
*/

/*
	条件变量初始化
	int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);

	条件变量销毁
	int pthread_cond_destroy(pthread_cond_t *cond);

	可向指定的条件变量发送信号
	二者对阻塞于 pthread_cond_wait()的多个线程对应的处理方式不同，
	pthread_cond_signal()函数至少能唤醒一个线程，
	而 pthread_cond_broadcast()函数则能唤醒所有线程。
	int pthread_cond_signal(pthread_cond_t *cond);
	int pthread_cond_broadcast(pthread_cond_t *cond);

	将线程设置为等待状态（阻塞）
	int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
*/

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>

static pthread_mutex_t mutex; //定义互斥锁
static pthread_cond_t cond;	  //定义条件变量
static int g_avail = 0;		  //全局共享资源

/* 消费者线程 */
static void *consumer_thread(void *arg)
{
	for (;;)
	{
		pthread_mutex_lock(&mutex); //上锁

	//如果这里没有没有这2句，那cpu将一直查询，这样浪费cpu性能，而使用条件变量的话，这里会阻塞
	//必须使用 while 循环，而不是 if 语句，这是一种通用的设计原则：当线程从 pthread_cond_wait()返回时，并不能确定判断条件的状态，应该立即重新检查判断条件，如果条件不满足，那就继续休眠等待。
		while (0 >= g_avail)
			pthread_cond_wait(&cond, &mutex); //等待条件满足,
		while (0 < g_avail)
			g_avail--;				  //消费
		pthread_mutex_unlock(&mutex); //解锁
	}
	return (void *)0;
}

/* 主线程（生产者） */
int main(int argc, char *argv[])
{
	pthread_t tid;
	int ret;

	/* 初始化互斥锁和条件变量 */
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);

	/* 创建新线程 */
	ret = pthread_create(&tid, NULL, consumer_thread, NULL);
	if (ret)
	{
		fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
		exit(-1);
	}

	for (;;)
	{
		pthread_mutex_lock(&mutex);	  //上锁
		g_avail++;					  //生产
		pthread_mutex_unlock(&mutex); //解锁
		pthread_cond_signal(&cond);	  //向条件变量发送信号
	}

	exit(0);
}